package com.dreamlike.nlp.DAO;

import com.dreamlike.nlp.Entity.WordInfo;
import io.vertx.core.Future;
import io.vertx.core.Promise;
import io.vertx.sqlclient.PreparedStatement;
import io.vertx.sqlclient.Row;
import io.vertx.sqlclient.RowSet;
import io.vertx.sqlclient.Tuple;
import io.vertx.sqlclient.impl.ArrayTuple;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.stream.Collectors;


@Component
public class NLPMapper {
    @Autowired
    private DatabasePool databasePool;

    public Future<String> getVector(String word){
        Promise<String> promise = Promise.promise();
        databasePool.getConnect()
                .onSuccess(sqlConnection -> {
                    sqlConnection.prepare("SELECT vector FROM nlp WHERE word = ?", preparedStatementAsyncResult -> {
                            if (preparedStatementAsyncResult.succeeded()) {
                                PreparedStatement preparedStatement = preparedStatementAsyncResult.result();
                                preparedStatement.query().execute(Tuple.of(word), rowSetAsyncResult -> {
                                    if (rowSetAsyncResult.succeeded()) {
                                        RowSet<Row> rows = rowSetAsyncResult.result();
                                        if (rows.rowCount() > 1) {
                                            preparedStatement.close();
                                            sqlConnection.close();
                                            promise.fail(new RuntimeException("SELECT vector FROM nlp WHERE word = ? has more than one result"));
                                        } else {
                                            for (Row row : rows) {
                                                promise.complete(row.getString("vector"));
                                            }
                                            preparedStatement.close();
                                            sqlConnection.close();
                                        }
                                    } else {
                                        promise.fail(rowSetAsyncResult.cause());
                                        preparedStatement.close();
                                        sqlConnection.close();
                                    }
                                });
                            } else {
                                sqlConnection.close();
                                promise.fail(preparedStatementAsyncResult.cause());
                            }
                        });
                })
                .onFailure(promise::fail);
        return promise.future();

    }

    public Future<Integer> insertWordInfo(List<WordInfo> wordInfoList){
        StringBuilder builder = new StringBuilder("INSERT INTO nlp_test (word, vector) VALUES ");
        for (int i = 0; i < wordInfoList.size(); i++) {
            builder.append("(?,?),");
        }
        String preparedSQL = builder.substring(0, builder.length() - 1);


        Promise<Integer> affectedRowsPromise = Promise.promise();
        Promise<RowSet<Row>> executeBatchPromise = Promise.promise();
        databasePool.getConnect()
                .onSuccess(connection -> {
                    Tuple tuple = Tuple.tuple();
                    wordInfoList.forEach(w -> tuple.addString(w.getWord()).addString(w.getVector()));
                    connection.preparedQuery(preparedSQL)
                            .execute(tuple, ar -> {
                                if (ar.succeeded()) {
                                    executeBatchPromise.complete(ar.result());
                                }else {
                                    executeBatchPromise.fail(ar.cause());
                                }
                                connection.close();
                            });
                })
                .onFailure(executeBatchPromise::fail);
        executeBatchPromise.future()
                .onSuccess(rs -> affectedRowsPromise.complete(rs.rowCount()))
                .onFailure(affectedRowsPromise::fail);
        return affectedRowsPromise.future();
    }



}
